
package com.hlkj.pay.app.merchant.ext.impl.yytpay.handler;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import java.io.*;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.util.*;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.util.URIUtil;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSONArray;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.app.merchant.IMerchantAccessAppService;
import com.hlkj.pay.app.merchant.ext.impl.leshua.constant.XmlUtils;
import com.hlkj.pay.app.merchant.ext.impl.yytpay.constant.HttpFdfsUtils;
import com.hlkj.pay.app.merchant.ext.impl.yytpay.constant.YytPayConstant;
import com.hlkj.pay.app.merchant.ext.impl.yytpay.dto.YytPayConfig;
import com.hlkj.pay.app.merchant.ext.impl.yytpay.dto.resp.YytImgResp;
import com.hlkj.pay.app.merchant.ext.impl.yytpay.dto.resp.YytOrderResp;
import com.hlkj.pay.common.PayResultCode;
import com.hlkj.pay.dto.merchant.MerchantAccessScene;
import com.hlkj.pay.dto.merchant.ProviderChannelFeeConfigList;
import com.hlkj.pay.enums.CommonEnum;
import com.hlkj.pay.enums.MerchantEnum;
import com.hlkj.pay.enums.PayEnums;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAccessCertInfoDO;
import com.hlkj.pay.infrastructure.model.order.PayOrderDO;
import com.hlkj.pay.infrastructure.model.pay.PayChannelDictDO;
import com.hlkj.pay.infrastructure.model.pay.PayWayDO;
import com.hlkj.pay.infrastructure.model.pay.ProviderChannelConfigDO;
import com.hlkj.pay.service.order.IPayOrderService;
import com.hlkj.pay.service.pay.IPayChannelDictService;
import com.hlkj.pay.util.DateUtils;
import com.hlkj.pay.util.ImageUtils;
import com.yst.m2.sdk.M2;
import com.yst.m2.sdk.M2Config;
import com.yst.m2.sdk.ReturnObj;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 银盈通服务商 商户进件参数处理
 * 
 * @author HlpayTeam
 * @date 2024/09/26 12:02
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class YytPayCommonParamsHandle {

    private final IPayOrderService payOrderService;

    private final IPayChannelDictService payChannelDictService;

    private final IMerchantAccessAppService merchantAccessAppService;

    /**
     * 获取结算方式
     * @param merchantFeeConfigList
     * @return
     */
    public Map<String,String> getsettleType(List<ProviderChannelFeeConfigList> merchantFeeConfigList){

        Map<String,String> feeMap = new HashMap<>();

        List<ProviderChannelFeeConfigList> settlementInfos = new ArrayList<>();
        List<BigDecimal> wechatFeeLsit = new ArrayList<>();
        List<BigDecimal> alipayFeeLsit = new ArrayList<>();
        // 支付类型分组
        Map<Integer, List<ProviderChannelFeeConfigList>> merchantFeeConfigMap = merchantFeeConfigList.stream()
                .filter(merchantFeeConfig -> merchantFeeConfig.getPayWayDO() != null)
                .collect(Collectors.groupingBy(merchantFeeConfig -> merchantFeeConfig.getPayWayDO().getType()));
        for (Map.Entry<Integer, List<ProviderChannelFeeConfigList>> entry : merchantFeeConfigMap.entrySet()) {
            switch (PayEnums.PAY_TYPE.fromByCode(entry.getKey())) {
                case WECHAT:
                    // 微信配置对象
                    for(ProviderChannelFeeConfigList feeConfig:entry.getValue()){
                        if(CommonEnum.YES_NO_TYPE.YES.getCode() == feeConfig.getStatus()){
                            wechatFeeLsit.add(feeConfig.getDefaultFeeConfigValue().getRateBase());
                        }
                    }
                    break;
                case ALIPAY:
                    for(ProviderChannelFeeConfigList feeConfig:entry.getValue()){
                        if(CommonEnum.YES_NO_TYPE.YES.getCode() == feeConfig.getStatus() ){
                            alipayFeeLsit.add(feeConfig.getDefaultFeeConfigValue().getRateBase());
                        }
                    }
                    break;
                case FUNCTION:
                    for(ProviderChannelFeeConfigList feeConfig:entry.getValue()){
                        if(feeConfig.getStatus() == 1){
                            settlementInfos.add(feeConfig);
                        }
                    }
                    break;
            }

            if(CollUtil.isNotEmpty(wechatFeeLsit)){
                BigDecimal wechat = Collections.min(wechatFeeLsit);
                feeMap.put("wechat",String.format("%.4f",NumberUtil.div(wechat.doubleValue(),100,4)));
            }else{
                feeMap.put("wechat","0.0038");
            }

            if(CollUtil.isNotEmpty(alipayFeeLsit)){
                BigDecimal alipay = Collections.min(alipayFeeLsit);
                feeMap.put("alipay",String.format("%.4f",NumberUtil.div(alipay.doubleValue(),100,4)));
            }else{
                feeMap.put("alipay","0.0038");
            }

            // 结算费率
            if(CollUtil.isNotEmpty(settlementInfos)){
                // 过滤D0 只能选一种,按优先顺序取
                Optional<ProviderChannelFeeConfigList> feeConfig_OTHER = settlementInfos.stream().filter(conf -> Objects.equals(conf.getPayWayDO().getCode(),MerchantEnum.SETTLE_CYCLE.D0.getPayWayCode())).findFirst();
                // D0
                if(feeConfig_OTHER.isPresent()){
                    feeMap.put("settle","D0");
                }else{
                    // D1 默认固定值 0
                    feeConfig_OTHER = settlementInfos.stream().filter(conf -> Objects.equals(conf.getPayWayDO().getCode(),MerchantEnum.SETTLE_CYCLE.D1.getPayWayCode())).findFirst();
                    if(feeConfig_OTHER.isPresent()){
                        feeMap.put("settle","D1");
                    }else{
                        // T1
                        feeConfig_OTHER = settlementInfos.stream().filter(conf -> Objects.equals(conf.getPayWayDO().getCode(),MerchantEnum.SETTLE_CYCLE.T1.getPayWayCode())).findFirst();
                        if(feeConfig_OTHER.isPresent()){
                            feeMap.put("settle","T1");
                        }
                    }
                }
            }
        }
        if(StrUtil.isEmpty(MapUtil.getStr(feeMap,"settle"))){
            feeMap.put("settle","T1");
        }
        return feeMap;
    }

    public Map<String,Object> getSettleProductInfo(List<ProviderChannelFeeConfigList> merchantFeeConfigList, boolean corporate){

        Map<String,Object> settle_data = new HashMap<>();

        List<ProviderChannelFeeConfigList> settlementInfos = new ArrayList<>();

        // 支付类型分组
        Map<Integer, List<ProviderChannelFeeConfigList>> merchantFeeConfigMap = merchantFeeConfigList.stream()
                .filter(merchantFeeConfig -> merchantFeeConfig.getPayWayDO() != null)
                .collect(Collectors.groupingBy(merchantFeeConfig -> merchantFeeConfig.getPayWayDO().getType()));
        for (Map.Entry<Integer, List<ProviderChannelFeeConfigList>> entry : merchantFeeConfigMap.entrySet()) {
            switch (PayEnums.PAY_TYPE.fromByCode(entry.getKey())) {
                case FUNCTION:
                    for(ProviderChannelFeeConfigList feeConfig:entry.getValue()){
                        if(feeConfig.getStatus() == 1){
                            settlementInfos.add(feeConfig);
                        }
                    }
                    break;
            }

            // 结算费率
            if(CollUtil.isNotEmpty(settlementInfos)){
                // 过滤D0 只能选一种,按优先顺序取
                Optional<ProviderChannelFeeConfigList> feeConfig_OTHER = settlementInfos.stream().filter(conf -> Objects.equals(conf.getPayWayDO().getCode(),MerchantEnum.SETTLE_CYCLE.D0.getPayWayCode())).findFirst();
                // D0
                if(feeConfig_OTHER.isPresent()){
                    settle_data.put("settlement_cycle","D0");
                    settle_data.put("withdrawal_rate",feeConfig_OTHER.get().getDefaultFeeConfigValue().getRateBase().toString());
                    settle_data.put("withdrawal_feemin",feeConfig_OTHER.get().getDefaultFeeConfigValue().getFixedRate().toString());
                    if(corporate){
                        settle_data.put("public_withdrawal_rate",feeConfig_OTHER.get().getDefaultFeeConfigValue().getRateBase().toString());
                        settle_data.put("public_withdrawal_feemin",feeConfig_OTHER.get().getDefaultFeeConfigValue().getFixedRate().toString());
                    }
                }else{
                    // D1 默认固定值 0
                    feeConfig_OTHER = settlementInfos.stream().filter(conf -> Objects.equals(conf.getPayWayDO().getCode(),MerchantEnum.SETTLE_CYCLE.D1.getPayWayCode())).findFirst();
                    if(feeConfig_OTHER.isPresent()){
                        settle_data.put("settlement_cycle","D1");
                        settle_data.put("withdrawal_rate",feeConfig_OTHER.get().getDefaultFeeConfigValue().getRateBase().toString());
                        settle_data.put("withdrawal_feemin",feeConfig_OTHER.get().getDefaultFeeConfigValue().getFixedRate().toString());
                        if(corporate){
                            settle_data.put("public_withdrawal_rate",feeConfig_OTHER.get().getDefaultFeeConfigValue().getRateBase().toString());
                            settle_data.put("public_withdrawal_feemin",feeConfig_OTHER.get().getDefaultFeeConfigValue().getFixedRate().toString());
                        }
                    }else{
                        // T1
                        feeConfig_OTHER = settlementInfos.stream().filter(conf -> Objects.equals(conf.getPayWayDO().getCode(),MerchantEnum.SETTLE_CYCLE.T1.getPayWayCode())).findFirst();
                        if(feeConfig_OTHER.isPresent()){
                            settle_data.put("settlement_cycle","T1");
                            settle_data.put("withdrawal_rate","0");
                            settle_data.put("withdrawal_feemin","0");
                            if(corporate){
                                settle_data.put("public_withdrawal_rate","0");
                                settle_data.put("public_withdrawal_feemin","0");
                            }
                        }
                    }
                }
            }
        }
        return settle_data;
    }

    /**
     * 回调签名校验
     * @param request
     * @param yytPayConfig
     * @return
     * @throws Exception
     */
    public String decrypt(HttpServletRequest request, YytPayConfig yytPayConfig, boolean checkSign) throws Exception {
        // 获取响应内容
        String responseText = XmlUtils.getContentFromRequestInputStream(request);
        log.info("responseText :{} ",responseText);
        if (StrUtil.isEmpty(responseText)) {
            return null;
        }

        Map<String,String> respData = JSONUtil.toBean(responseText,Map.class);
        // 获取业务数据
        String result = respData.get("data");
        // 获取响应数据签名
        String oldSign = respData.get("sign");
        // 拼接字符串
        String newSign = generateSign(respData,"MD5",yytPayConfig.getPayKey());
        log.info("MD5签名原始串：{}，签名结果：{}", oldSign, newSign);
        if(checkSign){
            if(!oldSign.equalsIgnoreCase(newSign)){
                log.info("签名校验失败！");
                return null;
            }
        }
        return result;
    }

    public String decrypt(String responseText, YytPayConfig yytPayConfig, boolean checkSign) throws Exception {
        if (StrUtil.isEmpty(responseText)) {
            return null;
        }

        Map<String,String> respData = JSONUtil.toBean(responseText,Map.class);
        // 获取业务数据
        String result = respData.get("data");
        // 获取响应数据签名
        String oldSign = respData.get("sign");
        // 拼接字符串
        String newSign = generateSign(respData,"MD5",yytPayConfig.getPayKey());
        log.info("MD5签名原始串：{}，签名结果：{}", oldSign, newSign);
        if(checkSign){
            if(!oldSign.equalsIgnoreCase(newSign)){
                log.info("签名校验失败！");
                return null;
            }
        }
        return result;
    }


    public String getAddService(YytPayConfig YytPayConfig){
        String polling = YytPayConfig.getPolling();
        if("1".equals(polling)){
            return polling;
        }
        return "0";
    }


    public CommonResult<YytPayConfig> yytPayConfig(ProviderChannelConfigDO providerChannelConfigDO, boolean test) {
        String paramsConfig = providerChannelConfigDO.getParamsConfig();
        if (StringUtils.isEmpty(paramsConfig)) {
            return CommonResult.error(PayResultCode.PAY_CHANNEL_CONFIG_NOT_EXITS);
        }
        // 配置转换
        YytPayConfig YytPayConfig = null;
        try {
            YytPayConfig = JsonUtils.parseObject(paramsConfig, YytPayConfig.class);
            return CommonResult.success(YytPayConfig);
        }
        catch (Exception e) {
            String format = String.format(PayResultCode.PAY_CHANNEL_CONFIG_ERROR.getMsg(), "银盈通");
            return CommonResult.error(PayResultCode.PAY_CHANNEL_CONFIG_NOT_EXITS.getCode(), format);
        }
    }



    public Integer licenseType(String code) {
        if (!StringUtils.hasText(code)) {
            return null;
        }
        // 营业执照类型：
        // 1：营业执照
        // 2：营业执照(多证合一)
        // 3：事业单位法人证书
        // 4：社会团体法人登记证书
        // 5：民办非企业单位登记证书
        // 6：基金会法人登记证书
        // 7：宗教活动场所登记证
        // 8：其他证书/批文/证明
        // 9：执业许可证/执业证
        // 10：基层群众性自治组织特别法人统一社会信用代码证
        // 11：农村集体经济组织登记证
        // 12：业主委员会备案证明

        /**
         * 营业执照（默认）------0
         * 政府部门下发的其他有效证明文件------1
         * 事业单位法人证书------2
         * 民办非企业单位登记证书------3
         * 基金会法人登记证书------4
         * 组织机构代码证------5
         * 统一社会信用代码证书------6
         * 社会团体登记证书(含社会团体法人登记证书、社会服务机构登记证书、工会法人资格证书)------7
         * 执业许可证/执业证(含律师事务所职业许可证、基层法律服务所执业证、司法鉴定许可证)------8
         * 基层群众性自治组织特别法人统一信用代码证------9
         * 农村集体经济组织登记证------10
         * 宗教活动场所登记证------11
         */
        switch (code) {
            case "1":
            case "2":
                return 0;
            case "3":
                return 2;
            case "4":
                return 7;
            case "5":
                return 3;
            case "6":
                return 4;
            case "7":
                return 11;
            case "8":
                return 1;
            case "9":
                return 8;
            case "10":
                return 9;
            case "11":
                return 10;
            default:
                return 0;
        }
    }

    public Integer certType(String code) {
        if (!StringUtils.hasText(code)) {
            return null;
        }
        // 营业执照类型：
        // 1:身份证
        // 2:护照
        // 3:军官证
        // 4:士兵证
        // 5:回乡证
        // 6:户口本
        // 7:外国护照
        // 8:其他
        // 9:暂住证
        // 10:警官证
        // 11:文职干部证
        // 12:港澳台同胞通行证
        // 13:外国人居留证
        // 14:台胞证
        // 15:港澳台居住证
        // 16：营业执照 （只有部分场景才会用到 如 受益人和股东）
        /**
         1：身份证；(默认)
         2：港澳台通行证；
         3：台湾身份证；
         4：香港身份证；
         5：澳门身份证；
         6：护照；
         7：居住证；
         9：其它法定文件
         */
        switch (code) {
            case "1":
                return 1;
            case "2":
                return 6;
            case "12":
                return 2;
            case "9":
                return 7;
            case "8":
                return 9;
            default:
                return 1;
        }
    }

    /**
     * 银盈通进件主体类型
     1: 企业商户
     2: 个体商户
     3: 小微商户
     *
     * 系统主体类型
     * 1：政府机构
     * 2：国营企业
     * 3：私营企业
     * 4：外资企业
     * 5：个体工商户
     * 6：其它组织
     * 7：事业单位
     * 8：业主委员会；
     */
    public Integer companyType(Integer type, MerchantEnum.MERCHANT_TYPE merchantType) {
        // 企业
        Integer companyType = null;
        switch (type){
            case 5:
                companyType = 2;
                break;
            case 1:
            case 2:
            case 3:
            case 4:
            case 6:
            case 8:
            case 7:
                companyType = 1;
                break;
        }

        return companyType;
    }


    /**
     * 获取受益人信息
     * @param uboInfoList
     * @param yytPayConfig
     * @return
     */
    public JSONArray getUnoArray(List<MerchantAccessCertInfoDO> uboInfoList, MerchantAccessCertInfoDO merchantAccessController,YytPayConfig yytPayConfig) {
        JSONArray JSONArray = new JSONArray();
        try{
            if(CollUtil.isEmpty(uboInfoList)){
                return null;
            }
            // 受益人
            for(MerchantAccessCertInfoDO uboInfo:uboInfoList){
                com.alibaba.fastjson.JSONObject dto = new com.alibaba.fastjson.JSONObject();
                dto.put("type","2");
                // // 受益人证件类型
                dto.put("id_type", "01");
                // 受益人名称
                dto.put("name",  uboInfo.getName());
                // 证件号码
                dto.put("id_no",  uboInfo.getCertNo());
                // // 证件正面照片
                // dto.put("id_from", getUploadMerQualUrl("",uboInfo.getCertFrontUrl(),yytPayConfig));
                // // 证件反面照片
                // dto.put("id_end", getUploadMerQualUrl("",uboInfo.getCertBackUrl(),yytPayConfig));
                // 受益人证件地址
                dto.put("address",  uboInfo.getAddress());
                // 受益人证件有效期开始时间
                dto.put("id_from", StrUtil.removeAll(uboInfo.getCertBeginDate(),"-"));
                if(uboInfo.getCertValidityType() == 1){
                    dto.put("id_end","99991231");
                }else{
                    dto.put("id_end",StrUtil.removeAll(uboInfo.getCertEndDate(),"-"));
                }
                JSONArray.add(dto);
            }

            // 控制人
            com.alibaba.fastjson.JSONObject dto = new com.alibaba.fastjson.JSONObject();
            dto.put("type","1");
            // // 受益人证件类型
            dto.put("id_type", "01");
            // 受益人名称
            dto.put("name",  merchantAccessController.getName());
            // 证件号码
            dto.put("id_no",  merchantAccessController.getCertNo());
            // // 证件正面照片
            // dto.put("id_from", getUploadMerQualUrl("",uboInfo.getCertFrontUrl(),yytPayConfig));
            // // 证件反面照片
            // dto.put("id_end", getUploadMerQualUrl("",uboInfo.getCertBackUrl(),yytPayConfig));
            // 受益人证件地址
            dto.put("address",  merchantAccessController.getAddress());
            // 受益人证件有效期开始时间
            dto.put("id_from", StrUtil.removeAll(merchantAccessController.getCertBeginDate(),"-"));
            if(merchantAccessController.getCertValidityType() == 1){
                dto.put("id_end","99991231");
            }else{
                dto.put("id_end",StrUtil.removeAll(merchantAccessController.getCertEndDate(),"-"));
            }
            JSONArray.add(dto);

        }catch (Exception e){
            throw new RuntimeException("yytpay getUnoArray 异常", e);
        }
        return JSONArray;
    }

    /**
     * 过去指定场景类型的数据
     * @param sceneList
     * @param senceType
     * @return
     */
    public  MerchantAccessScene getMerchantAccessSceneValue(List<MerchantAccessScene> sceneList, Integer senceType){
        if(CollUtil.isNotEmpty(sceneList)){
            for(MerchantAccessScene accessScene:sceneList){
                if(accessScene.getType() == senceType){
                    return accessScene;
                }
            }

        }
        return null;
    }

    /**
     * 0：对公账户 1：对私法人账户 2：对私非法人账户
     * @param type
     * @return
     */
    public Integer getBankAccountType(Integer type){
        Integer bankAccountType = null;
        if(type == null){
            return bankAccountType;
        }
        switch (type){
            case 0:
                bankAccountType = 2;
                break;
            default:
                bankAccountType = 1;
                break;
        }
        return bankAccountType;
    }

    /**
     * 银盈通上传图片获取merQualUrl
     * @param key  key值 用于错误提示
     * @param filePath  本地路劲/https
     * @param YytPayConfig
     * @return
     */
    public String getUploadMerQualUrl(String key,String filePath, YytPayConfig YytPayConfig) {

        String errorMsg = "银盈通 Upload 上传文件格式异常 , "+key+ " is null";
        if(StrUtil.isEmpty(filePath)){
            log.error(errorMsg);
            throw new RuntimeException(errorMsg);
        }

        File file = null;
        if(HttpUtil.isHttp(filePath)  || HttpUtil.isHttps(filePath) ){
            // 创建临时文件
            file =  FileUtil.createTempFile("."+ ImageUtils.getFileExtension(filePath),true);
            // 文件流copy到临时文件
            HttpUtil.downloadFile(filePath,file);
        }else{
            file = FileUtil.newFile(filePath);
        }

        if(FileUtil.isEmpty(file)){
            log.error(errorMsg);
            throw new RuntimeException(errorMsg);
        }

        String result = uploadPicApi(file,YytPayConfig);
        log.info("银盈通 Upload 上传文件 filePath :{}, 配置 :{}, 返回参数 :{}",filePath, JSONUtil.toJsonStr(YytPayConfig),result);
        if(StrUtil.isNotEmpty(result)){
            return result;
        }else{
            throw new RuntimeException("银盈通 Upload 上传文件异常 : "+filePath);
        }
    }


    /**
     * 获取支付方式
     * @param payWayDO
     * @return
     */
    public String getPayWay(PayWayDO payWayDO){
        String payway = null;
        // 支付方式枚举
        PayEnums.PAY_TYPE payType = PayEnums.PAY_TYPE.fromByCode(payWayDO.getType());
        switch (payType){
            case WECHAT:
                payway = "02";
                break;
            case ALIPAY:
                payway = "01";
                break;
        }

        return payway;
    }

    public String generateSign(Map<String, String> params, String signType, String key) {
        // 允许的参数列表
        String[] allowedParams = {"charset", "format", "req_no", "sign_type", "version", "timestamp","method", "data", "app_id"};

        Map<String, String> filteredParams = new HashMap<>();
        for (String param : allowedParams) {
            if (params.containsKey(param)) {
                filteredParams.put(param, params.get(param));
            }
        }
        //非JAVA代码开发者注意！此处代码会将上述中的加签内容按照字典表进行重新排序！
        TreeMap<String, String> sortedParams = new TreeMap<>(filteredParams);

        StringBuilder paramString = new StringBuilder();
        for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
            paramString.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
        }
        String baseString = paramString.toString().trim();
        if (baseString.endsWith("&")) {
            baseString = baseString.substring(0, baseString.length() - 1);
        }

        String signString = baseString + "&key=" + key;
        try {
            MessageDigest md = MessageDigest.getInstance(signType);
            byte[] hashBytes = md.digest(signString.getBytes("UTF-8"));
            StringBuilder hexString = new StringBuilder();
            for (byte b : hashBytes) {
                String hex = String.format("%02x", b);
                hexString.append(hex);
            }
            return hexString.toString().toUpperCase();
        } catch (Exception e) {
            throw new RuntimeException("签名生成失败", e);
        }
    }

    public YytOrderResp sendPostRequest(String urlStr, String json, String method,YytPayConfig yytPayConfig,PayOrderDO payOrderDO,String terType,String brand) throws Exception {
        Map<String, String> params = new HashMap<>();
        params.put("method", method.split("@")[1]);
        params.put("timestamp", DateUtils.getDateString(DatePattern.NORM_DATETIME_PATTERN));
        params.put("charset", "UTF-8");
        params.put("sign_type", "MD5");
        params.put("version", "1.0");
        params.put("req_no", IdUtil.simpleUUID());
        params.put("format", "JSON");
        params.put("app_id", yytPayConfig.getPayAppId());
        params.put("data",json);
        params.put("sign", generateSign(params, "MD5", yytPayConfig.getPayKey()));
        params.put("client_ip", payOrderDO.getClientIp());
        params.put("terminal_type", "4");
        params.put("browser_brand", brand);

        return sendPostRequest(urlStr,JSONUtil.toJsonStr(params),method);
    }

    public YytOrderResp sendPostRequest(String urlStr, String json, String method) throws Exception {
        log.info("sendPostRequest  urlStr:{}, data:{} ,method:{}",urlStr,json,method);
        URL url = new URL(urlStr);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();

        conn.setRequestMethod("POST");
        conn.setRequestProperty("Accept", "application/json");
        conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
        conn.setRequestProperty("method", method); // 设置请求头method
        conn.setDoOutput(true);

        try (DataOutputStream wr = new DataOutputStream(conn.getOutputStream())) {
            wr.write(json.getBytes("UTF-8"));
            wr.flush();
        }

        int responseCode = conn.getResponseCode();
        if (responseCode != HttpURLConnection.HTTP_OK) {
            throw new RuntimeException("HTTP请求失败，状态码：" + responseCode);
        }

        try (BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {
            String inputLine;
            StringBuilder response = new StringBuilder();
            while ((inputLine = in.readLine()) != null) {
                response.append(inputLine);
            }
            String result = response.toString();
            if(StrUtil.isNotEmpty(result)){
                return JSONUtil.toBean(result,YytOrderResp.class);
            }
        }
        return null;
    }



    /**
     * 获取渠道类型
     * @param payWayDO
     * @return
     */
    public String getPayChannel(PayWayDO payWayDO){
        String  payChannel = null;
        PayEnums.PAY_TYPE payType = PayEnums.PAY_TYPE.fromByCode(payWayDO.getType());
        switch(payType){
            case WECHAT:
                payChannel = "mfbwx";
                break;
            case ALIPAY:
                payChannel = "mfbzfb";
                break;
        }
        return payChannel;
    }


    public String getInterfaceType(PayWayDO payWayDO){
        String  payChannel = null;
        PayEnums.PAY_TYPE payType = PayEnums.PAY_TYPE.fromByCode(payWayDO.getType());
        switch(payType){
            case WECHAT:
                payChannel = "01";
                break;
            case ALIPAY:
                payChannel = "02";
                break;
        }
        return payChannel;
    }




    public PayOrderDO queryPayOrder(String orderId){
        return payOrderService.queryPayOrderNoCache(orderId);
    }

    /**
     * 时间戳转DateTime
     * @param timestamp
     * @return
     */
    public long formatTimestamp(long timestamp,boolean minute){
        long second = (timestamp-System.currentTimeMillis())/1000;
        if(minute){
            return second/60;
        }
        return second;
    }





    /**
     * 获取轮询商户号
     * @param subMchId
     * @param payType
     * @return
     */
    public String getMchAtId(String subMchId,PayEnums.PAY_TYPE payType){
        return merchantAccessAppService.randomMchId(subMchId,payType);
    }




    public ReturnObj requestPostApi(String url,String apiId,String data, YytPayConfig YytPayConfig){
        log.info("请求地址:{},接口ID：{},请求参数:{} ",url,apiId,data);
        // 初始化 M2Config
        M2Config config = new M2Config();
        config.setAid(YytPayConfig.getAppId());
        config.setApp_key(YytPayConfig.getAppKey());
        config.setUrl_ca(url);
        config.setOpen_ca(true);
        config.setDebug(false);
        config.setPrivate_key_file(YytPayConfig.getPrivateKeyPath());
        config.setPrivate_key_pwd(YytPayConfig.getPrivateKeyPwd());
        config.setPublic_key_file(YytPayConfig.getPublicKeyPath());
        return M2.build(config).send(apiId,data);
    }


    /**
     * 获取总行名称
     * @param channelCode
     * @param dictKey
     * @param bankcode
     * @return
     */
    public String getBankName(String channelCode,String dictKey,String bankcode){
        PayChannelDictDO payChannelDictDO =  payChannelDictService.queryChannelDict(channelCode,dictKey,bankcode);
        return payChannelDictDO.getDictDesc();
    }

    /**
     * 上传图片
     * @param file
     * @param YytPayConfig
     * @return
     */
    public static String uploadPicApi(File file,YytPayConfig YytPayConfig){
        // 封装参数
        Map<String, String> textMap = new HashMap<>();
        textMap.put("aid",YytPayConfig.getAppId());
        // 图片信息
        Map<String,InputStream> data = new HashMap<>();
        data.put(file.getName(),FileUtil.getInputStream(file));
        // 调佣接口
        String res = HttpFdfsUtils.formUpload(YytPayConstant.PIC_UPLOAD_RUL, textMap, data, null);
        if(StrUtil.isNotEmpty(res)){
            YytImgResp imgResp = JSONUtil.toBean(res,YytImgResp.class);
            if(YytPayConstant.OK.equals(imgResp.getErr_code())){
                return imgResp.getImage_url();
            }
        }
        return null;
    }

    public static void main(String[] args) throws JsonProcessingException, URIException {
        YytPayConfig YytPayConfig = new YytPayConfig();
        YytPayConfig.setAppId("8a1ca8a382b0667f0196be3bd5fd0391");
        //图片
        // String img = "E:/cert/gift_8.png";
        // File file = FileUtil.newFile(img);
        //
        // String result = uploadPicApi(file,YytPayConfig);
        // System.out.println(result);

        // 1. 生成基础参数

        // 2. 添加固定参数
        String  ss = String.valueOf(NumberUtil.div(new BigDecimal(1).doubleValue(),100,4));
        System.out.println(ss);

        String str = "http:2222?orderId=202505271930480198270147&env=H5";
        System.out.println(URIUtil.encodePathQuery(str));

    }


}
